	/*
	 * Calcula la distancia de Lavenstein entre dos cadenas (el numero de inserciones, 
	 * eliminaciones y sustituciones necesarias para transformar la primera cadena en 
	 * la segunda).
	 * 
	 * */

package com.servicios.negocio.app.comun.impl;

import com.core.app.modelo.ICatalogo;
import com.core.app.servicios.ExcepcionServicio;
import com.objetos.transf.datos.app.comun.ValidarCadenasSimilaresPeticion;
import com.objetos.transf.datos.app.comun.ValidarCadenasSimilaresRespuesta;
import com.servicios.negocio.app.comun.ValidarCadenasSimilares;

public class ValidarCadenasSimilaresImpl implements ValidarCadenasSimilares {
	
	@Override
	public ValidarCadenasSimilaresRespuesta ejecutar(
			ValidarCadenasSimilaresPeticion peticion) throws ExcepcionServicio {
		
		ValidarCadenasSimilaresRespuesta validarCadenasSimilaresRespuesta = new ValidarCadenasSimilaresRespuesta();
		
		// System.out.println("----- EJECUTANDO VALIDACION DE CADENAS ------");
		// System.out.println("----- CADENAS EXISTENTE: " + peticion.getCadenaExistente());
		// System.out.println("----- CADENA NUEVA: " + peticion.getCadenaNueva());
		
		if(peticion.getCatalogo() != null ){ // Se valida el modelo enviado en la peticion
			System.out.println("----- VALIDANDO CATALOGO COMPLETO ------");
			for(Object entidad : peticion.getCatalogo()){
				if(calcularDistanciaLevenshtein(((ICatalogo)entidad).getDescripcion(), peticion.getCadenaNueva()) < peticion.getUmbral()){
					validarCadenasSimilaresRespuesta.setExisteCadenaSimilar(true);
					break;
				}
			}
		}else{ // Cuando solo se validan dos cadenas enviadas en la peticion
			System.out.println("----- VALIDANDO CADENAS -----");
			validarCadenasSimilaresRespuesta.setResultadoComputo(calcularDistanciaLevenshtein(peticion.getCadenaExistente(), peticion.getCadenaNueva()));
			if(validarCadenasSimilaresRespuesta.getResultadoComputo() < peticion.getUmbral()){
				validarCadenasSimilaresRespuesta.setExisteCadenaSimilar(true);
			}else{
				validarCadenasSimilaresRespuesta.setExisteCadenaSimilar(false);
			}
		}
		
		
		return validarCadenasSimilaresRespuesta;
	}
	
	private int calcularDistanciaLevenshtein(String cadenaExistente,String cadenaNueva) {
		int[][] distancia = new int[cadenaExistente.length() + 1][cadenaNueva.length() + 1];
 
		for (int i = 0; i <= cadenaExistente.length(); i++)
			distancia[i][0] = i;
		for (int j = 1; j <= cadenaNueva.length(); j++)
			distancia[0][j] = j;
 
		for (int i = 1; i <= cadenaExistente.length(); i++)
			for (int j = 1; j <= cadenaNueva.length(); j++)
				distancia[i][j] = minimo(
						distancia[i - 1][j] + 1,
						distancia[i][j - 1] + 1,
						distancia[i - 1][j - 1]+ ((cadenaExistente.charAt(i - 1) == cadenaNueva.charAt(j - 1)) ? 0 : 1));
 
		return distancia[cadenaExistente.length()][cadenaNueva.length()];    
	}
	
	private int minimo(int a, int b, int c) {
		return Math.min(Math.min(a, b), c);
	}
}
